2oneweek.dev

06. useEffect Hook

    Tags

  • React
06. useEffect Hook thumbnail

hook useEffect()

  • 부수효과를 처리하기 위한 훅
  • 부수효과란 외부의 상태를 변경하는 것을 의미한다. 서버 API를 호출하거나, 이벤트 핸들러를 등록하는 것이 부수효과다.
  • 부수효과가 많은 프로젝트는, 순수 함수가 가지는 여러 장점을 포기하게 되는 등, 유닛테스트가 힘들어진다.
useEffect(() => { console.log("side effect"); }, [variable]);
  • 첫 번째 매개변수로 함수를 입력한다. 이 함수는 컴포넌트가 렌더링 된 "후"에 호출된다. 더 정확하게 하면, 렌더링 결과가 실제 돔에 반영되고 비동기로 호출된다. 이 함수를 부수 효과 함수라고 한다.
  • 두 번째 매개변수로 배열을 입력한다. 이 배열은 의존성 배열이라고 부른다. 리-렌더가 발생할 때 마다 부수효과 함수가 실행되는 것은 매우 비효율적이다.(부수효과함수가 하는 일은 API 호출과 같은 일이므로)
    • 이 배열의 요소가 변화될 때마다, 부수효과함수가 실행되도록 하는 것이다.
    • 만약 배열이 비어있으면, 컴포넌트가 생성될 때만 부수효과 함수가 호출된다.




부수효과함수의 반환

useEffect(() => { console.log("side effect"); return () => { console.log("called"); }; }, [variable]);
  • 부수효과가 반환하는 함수 return () => {console.log("called") }다음 부수효과함수가 호출되기 "직전"에 호출되거나 또는, 컴포넌트가 사라지기 직전, 즉, 컴포넌트가 unmount되기 직전에 마지막으로 호출된다.

    • 따라서 이벤트 핸들러 등록과 제거에 유용하다.
    useEffect(() => { const handler = () => { console.log("클릭 핸들러"); }; window.addEventListener("click", handler); return () => { window.removeEventListener("click", handler); }; }, []);
    • 컴포넌트가 생성될 때, 이벤트 핸들러를 등록한다.
    • 컴포넌트가 사라질 때, 이벤트 핸들러를 제거한다

부수효과함수와 async await

useEffect(async () => { const data = await fetchUser(userId); setUser(data); }, [userId]);

부수효과 함수의 "반환값"은 항상 함수타입이어야 한다. 부수효과 함수는 반환을 한다면 함수만 할 수 있고, 반환된 함수는 부수효과 함수과 호출되기 직전과 컴포넌트가 사라지기 직전에 호출된다. async 함수는 promise 객체를 반환하기 때문에 부수효과 함수가 될 수 없다.


만약 async await를 사용하고 싶다면 함수를 하나 만들어서 호출해 주는 방식을 사용해야 한다.

useEffect(() => { async function fetchAndSetUser() { const data = await fetchUser(userId); setUser(data); } fetchAndSetUser(); }, [userId]);

만약 바깥에 있는 함수를 호출해주는 방식이라면, 의존성 배열에 "함수"를 입력해야 한다.

  • 이 함수 안에서는 속성값과 상태값을 사용하고 있기 때문이다.
async function fetchAndSetUser() { const data = await fetchUser(userId); setUser(data); } useEffect(() => { fetchAndSetUser(); }, [fetchAndSetUser]);
  • 그러나 이 함수는 컴포넌트가 렌더링될 때마다 새로 생성되면서 useEffect가 쓸데없이 동작하게 된다.
  • 이때 useCallback 훅을 사용한다.
const fetchAndSetUser = useCallback( async function fetchAndSetUser() { const data = await fetchUser(userId); setUser(data); }, [userId] ); useEffect(() => { fetchAndSetUser(); }, [fetchAndSetUser]);



의존성 배열

  • useEffect에 배열을 인자로 넘겨주지 않으면, 렌더링 될 때마다 부수효과함수가 실행된다.
  • []로 넘겨주면 마운트 된 후에 한 번만 호출된다.
  • 의존성 배열에서 버그가 많이 발생하기 때문에, 리액트에서 eslint로 룰을 만들었다. create-react-app에는 기본적으로 포함되어 있다.

가능하다면 의존성 배열을 사용하지 않는 것이 좋다. 의존성 배열을 관리하는게 매우 복잡하기 때문이다. 특히 함수를 의존성 배열에 넣는 순간 useCallback등을 사용해서 신경써야되기 때문이다. 의존성배열을 사용하는 대신, 부수효과 함수 내에서 실행 시점을 조절하자.

useEffect(() => { if (!user || user.id !== userId) { fetchAndSetUser(); } });
Written by@2-one-week
현재 블로그 개발 중

GitHubLinkedIn